package com.wzk.travelspringboot.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wzk.travelspringboot.common.LogToFile;
import com.wzk.travelspringboot.common.RedisConstant;
import com.wzk.travelspringboot.dao.ScenicDAO;
import com.wzk.travelspringboot.dao.ScenicTypeDAO;
import com.wzk.travelspringboot.dto.PageQuery;
import com.wzk.travelspringboot.dto.Result;
import com.wzk.travelspringboot.dto.ScenicDTO;
import com.wzk.travelspringboot.dto.ViewDTO;
import com.wzk.travelspringboot.entity.Scenic;
import com.wzk.travelspringboot.service.ScenicService;
import com.wzk.travelspringboot.vo.PageResult;
import com.wzk.travelspringboot.vo.ScenicTypeVO;
import com.wzk.travelspringboot.vo.ScenicVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import java.util.stream.Collectors;

/**
 * @Author: WangZiKang
 * @Date: 2025/1/8 21:35
 */
@Slf4j
@Service(value = "scenicServiceImpl")
@RequiredArgsConstructor
public class ScenicServiceImpl extends ServiceImpl<ScenicDAO, Scenic> implements ScenicService {

    public static final Logger logger = Logger.getLogger(ScenicTypeServiceImpl.class.getName());

    private final ScenicDAO scenicDAO;

    private final StringRedisTemplate stringRedisTemplate;

    private final ScenicTypeDAO scenicTypeDAO;

    private final ObjectMapper objectMapper;

    @Override
    public Result insert(ScenicDTO dto) {
        //1.判断此名称的景区是否已经存在了
        int i = scenicDAO.queryScenicCountByName(dto.getName());
        if (i > 0){
            return Result.failed("此景区数据已经存在！");
        }
        //2.判断类别是否存在
        int j = scenicTypeDAO.queryCountByTypeName(dto.getType());
        if (j <= 0){
            return Result.failed("此景区类型不存在！");
        }
        //3.封装结果并保存数据
        Scenic scenic = BeanUtil.copyProperties(dto, Scenic.class);
        scenic.setScore(1);
        scenic.setView(0L);
        scenic.setCreateTime(LocalDateTime.now());
        scenic.setUpdateTime(LocalDateTime.now());
        boolean b = save(scenic);
        if (!b){
            return Result.failed("添加失败！出现未知错误");
        }
        return Result.success("添加成功！",null);
    }

    @Override
    public Result queryAll(PageQuery page) {
        try {
            // 创建LambdaQueryChainWrapper进行更安全的查询
            LambdaQueryChainWrapper<Scenic> queryWrapper = lambdaQuery();
            
            // 按浏览量降序排序（热门景点优先）
            queryWrapper.orderByDesc(Scenic::getView);
            
            // 处理过滤条件
            if (page.getFilter() != null && !page.getFilter().isEmpty()) {
                Map<String, Object> filter = page.getFilter();
                
                // 处理景区类型过滤
                if (filter.containsKey("type") && filter.get("type") != null) {
                    String type = String.valueOf(filter.get("type"));
                    if (!type.isEmpty()) {
                        queryWrapper.eq(Scenic::getType, type);
                    }
                }
                
                // 处理地区过滤
                if (filter.containsKey("area") && filter.get("area") != null) {
                    String area = String.valueOf(filter.get("area"));
                    if (!area.isEmpty()) {
                        queryWrapper.eq(Scenic::getArea, area);
                    }
                }
            }
            
            // 创建分页对象并执行查询
            Page<Scenic> pageObj = new Page<>(page.getPageNum(), page.getPageSize());
            Page<Scenic> result = queryWrapper.page(pageObj);
            
            // 处理查询结果为空的情况
            if (result.getRecords().isEmpty()) {
                PageResult<ScenicVO> emptyResult = new PageResult<>();
                emptyResult.setTotal(0L);
                emptyResult.setPageCount(0L);
                emptyResult.setData(Collections.emptyList());
                return Result.success("未找到任何数据!", emptyResult);
            }
            
            // 计算总页数
            Long total = result.getTotal();
            long pageSize = page.getPageSize();
            long pageCount = (total + pageSize - 1) / pageSize;
            
            // 转换为VO对象
            List<ScenicVO> vos = result.getRecords().stream()
                .map(scenic -> BeanUtil.copyProperties(scenic, ScenicVO.class))
                .collect(Collectors.toList());
            
            // 封装结果
            PageResult<ScenicVO> pageResult = new PageResult<>();
            pageResult.setTotal(total);
            pageResult.setPageCount(pageCount);
            pageResult.setData(vos);
            
            return Result.success("查询成功", pageResult);
        } catch (Exception e) {
            log.error("查询景区列表时发生异常: ", e);
            LogToFile.logToFile("queryAll出现异常:" + e.getMessage(), logger, "query_all_err");
            return Result.failed("查询景区列表失败: " + e.getMessage());
        }
    }

    @Override
    public Result queryById(Long aLong) {
        //1.根据id查询是否存在
        Scenic scenic = getById(aLong);
        //2.判断是否存在
        if (scenic == null){
            return Result.failed("数据不存在！");
        }
        ScenicVO vo = BeanUtil.copyProperties(scenic, ScenicVO.class);
        return Result.success(vo);
    }

    @Override
    public Result queryLikeName(Integer pageNum, Integer pageSize, String name) {
        try{
            //0.查询redis判断数据是否存在
            String s = stringRedisTemplate.opsForValue().get(RedisConstant.SCENIC_LIKE_KEY + name);
            if (StrUtil.isBlank(s)){
                //1.模糊查询
                List<Scenic> res = scenicDAO.queryLikeName("%"+name+"%");
                //2.判断结果是否为空
                if (res.isEmpty()){
                    PageResult<ScenicVO> pageResult = new PageResult<ScenicVO>();
                    pageResult.setTotal(0L);
                    pageResult.setPageCount(0L);
                    pageResult.setData(Collections.emptyList());
                    return Result.success("未找到任何数据!", pageResult);
                }
                //不是空转换成vo缓存redis
                List<ScenicVO> vos = res.stream().map(scenic -> BeanUtil.copyProperties(scenic, ScenicVO.class)).collect(Collectors.toList());
                stringRedisTemplate.opsForValue().set(RedisConstant.SCENIC_LIKE_KEY+name,objectMapper.writeValueAsString(vos),RedisConstant.SCENIC_LIKE_TIME, TimeUnit.MINUTES);
                //3.获取总条数
                int total = res.size();
                int pageCount = (int) ((total % 5 == 0) ? total / 5 : (total / 5) + 1);
                // 4. 计算当前页的起始索引和结束索引
                int fromIndex = (pageNum - 1) * pageSize;
                int toIndex = Math.min(pageNum * pageSize, total);
                // 5. 获取当前页的数据
                List<ScenicVO> pageData = vos.subList(fromIndex, toIndex);
                //6.封装参数返回
                PageResult<ScenicVO> pageResult = new PageResult<>();
                pageResult.setData(pageData);
                pageResult.setTotal((long) total);
                pageResult.setPageCount((long) pageCount);
                return Result.success("查询成功",pageResult);
            }else {
                //缓存不是null
                List<ScenicVO> res = objectMapper.readValue(s, new TypeReference<List<ScenicVO>>() {});
                //3.获取总条数
                int total = res.size();
                int pageCount = (int) ((total % 5 == 0) ? total / 5 : (total / 5) + 1);
                // 4. 计算当前页的起始索引和结束索引
                int fromIndex = (pageNum - 1) * pageSize;
                int toIndex = Math.min(pageNum * pageSize, total);
                // 5. 获取当前页的数据
                List<ScenicVO> pageData = res.subList(fromIndex, toIndex);
                //6.封装参数返回
                PageResult<ScenicVO> pageResult = new PageResult<>();
                pageResult.setData(pageData);
                pageResult.setTotal((long) total);
                pageResult.setPageCount((long) pageCount);
                return Result.success("查询成功",pageResult);
            }
        }catch (Exception e){
            LogToFile.logToFile("queryLikeName出现异常:"+e.getMessage(),logger,"like_name_err");
            return Result.failed("出现错误!");
        }
    }

    @Override
    public void view(ViewDTO dto) {
        //1.查询判断景区是否存在
        Scenic scenic = getById(dto.getId());
        if (scenic == null){
            return;
        }
        //2.判断用户是否查看过了
        Boolean b = stringRedisTemplate.opsForSet().isMember(RedisConstant.SCENIC_VIEW_KEY + dto.getId(), dto.getUserId().toString());
        if (Boolean.FALSE.equals(b)){
            //该用户没有浏览过 记录id到redis
            stringRedisTemplate.opsForSet().add(RedisConstant.SCENIC_VIEW_KEY+dto.getId(),dto.getUserId().toString());
            //数据库浏览量+1
            int i = scenicDAO.incrView(dto.getId());
            if (i <= 0){
                throw new RuntimeException("浏览量计数失败!");
            }
        }
    }

    @Override
    public Result all() {
        //查询所有景区数据
        List<Scenic> sLists = query().list();
        if (sLists.isEmpty()){
            return Result.success(Collections.emptyList());
        }
        return Result.success(sLists);
    }
}
